package thread;

import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 刘远望
 * Date: 2025-05-24
 * Time: 23:36
 */
//线程安全：内存可见性
//这里涉及到编译器优化的问题 可能会优化错误
public class Demo21 {
    public static int flag = 0;

    public static void main1(String[] args) {
        Thread thread1 = new Thread(() -> {
            //不加sleep由于循环次数太快修改之前结果都一样 JVM就会优化
            //这里可能会被优化成从内存读取flag改为直接读取寄存器中的flag值提升效率
            while (flag == 0) {
                try {
                    Thread.sleep(1);//加上sleep由于sleep消耗的时间远大于load flag的操作 就没有必要优化 所以不会产生内存可见性问题 这是一种解决方法 但是太鸡肋
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("thread1 线程结束");
        });

        Thread thread2 = new Thread(() -> {
            //针对flag进行修改
            Scanner scanner = new Scanner(System.in);
            System.out.println("输入要修改的flag值：");
            flag = scanner.nextInt();
        });

        /**
         * 一个线程读取 一个线程修改
         * 修改的线程值 并没有被读取的线程读取到
         * 这就是内存可见性问题
         */
        thread1.start();
        thread2.start();
    }

    //第二种解决方法也是最常用的方法用volatile关键字
    //通过这个关键字修饰的变量 此时编译器对这个变量的读取操作就不会被优化成寄存器读取(thread2修改了flag thread1就能及时看到)
    //volatile只能解决内存可见性问题，不能解决原子性问题
    private volatile static int flag2 = 0;
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            while (flag2 == 0) {

            }
            System.out.println("thread1 线程结束");
        });

        Thread thread2 = new Thread(() -> {
            //针对flag进行修改
            Scanner scanner = new Scanner(System.in);
            System.out.println("输入要修改的flag值：");
            flag2 = scanner.nextInt();
        });

        thread1.start();
        thread2.start();
    }
}

